import React, { useEffect, useState, useRef } from "react";
import { Canvas } from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
import * as THREE from "three";
import { Select } from "antd";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import "./AiHome.css";

const ThreeScene: React.FC = () => {
  const [modelUrl] = useState("models/合并.glb");
  // const [modelUrl] = useState("http://localhost:5173/models/合并.glb");
  // const [modelUrl] = useState('http://localhost:5173/models/小帅.glb');
  // const [modelUrl] = useState("http://localhost:5173/models/小帅帅.glb");
  const [index, setIndex] = useState(0);
  const [selectedAction, setSelectedAction] = useState([]);
  const dragbox = useRef<HTMLDivElement | null>(null);
  useEffect(() => {
    // 定义 handleMouseDown 函数，开始拖动的过程
    const handleMouseDown = (e: MouseEvent) => {
      // 如果 dragbox 不存在，则退出函数
      if (!dragbox.current) return;

      // 计算鼠标相对于 dragbox 的初始位置
      const x = e.pageX - dragbox.current.offsetLeft;
      const y = e.pageY - dragbox.current.offsetTop;

      // 定义 handleMouseMove 函数，在拖动过程中更新 dragbox 的位置
      const handleMouseMove = (e: MouseEvent) => {
        // 如果 dragbox 不存在，则退出函数
        if (!dragbox.current) return;

        // 根据鼠标的位置，实时更新 dragbox 的 left 和 top 样式，拖动它
        dragbox.current.style.left = `${e.pageX - x}px`;
        dragbox.current.style.top = `${e.pageY - y}px`;
      };

      // 定义 handleMouseUp 函数，停止拖动
      const handleMouseUp = () => {
        // 移除 document 上的 mousemove 和 mouseup 事件监听器
        document.removeEventListener("mousemove", handleMouseMove);
        document.removeEventListener("mouseup", handleMouseUp);
      };

      // 在 document 上添加 mousemove 和 mouseup 事件监听器来处理拖动
      document.addEventListener("mousemove", handleMouseMove);
      document.addEventListener("mouseup", handleMouseUp);
    };

    // 如果 dragbox 存在，给它添加 mousedown 事件监听器
    if (dragbox.current) {
      dragbox.current.addEventListener("mousedown", handleMouseDown);
    }

    // 清理函数，在组件卸载时移除事件监听器，防止内存泄漏
    return () => {
      if (dragbox.current) {
        dragbox.current.removeEventListener("mousedown", handleMouseDown);
      }
    };
  }, [dragbox]); // 当 dragbox 引用发生变化时，重新运行这个 effect

  // 切换不同模型的函数
  const handleChange = (value: string) => {
    for (let i = 0; i <= selectedAction.length; i++) {
      if (value === "你没时间了") {
        setIndex(0);
      } else if (value === "转圈圈") {
        setIndex(1);
      } else if (value === "给我爬") {
        setIndex(3);
      } else if (value === "小跳一下") {
        setIndex(2);
      }
    }
  };

  // 定义模型状态，初始为null，加载成功后为THREE.Group类型的实例，表示3D模型对象
  const [model, setModel] = useState<THREE.Group | null>(null);
  // 定义动画混合器的引用，初始为null，用于控制模型动画的播放、暂停等操作
  // const mixer = useRef<THREE.AnimationMixer | null>(null);
  // 定义动画是否暂停的状态，初始为false，用于控制动画的暂停和恢复
  const [isAnimationPaused] = useState(false);
  // 用于记录requestAnimationFrame的ID，方便在切换动画等情况时取消之前的动画更新循环
  let animationFrameId: number | null = null;

  // 记录当前正在播放的动画动作，方便在切换动画时进行精准控制
  let currentAction: THREE.AnimationAction | null = null;
  useEffect(() => {
    // 创建一个全局的动画混合器实例，用于控制模型的动画
    const mixer = new THREE.AnimationMixer(null);

    // 创建GLTFLoader实例，用于加载GLTF格式的模型文件
    const loader = new GLTFLoader();

    // 加载模型文件，加载成功后处理模型的相关属性和动画
    loader.load(
      modelUrl,
      (gltf) => {
        // 获取加载后的模型对象
        const loadedModel = gltf.scene;

        // 输出加载的动画数据到控制台
        // console.log(gltf.animations, "gltf");

        // 设置选中的动画动作
        setSelectedAction(gltf.animations);

        // 设置模型的缩放比例和位置
        const scale = 2.5;
        loadedModel.scale.set(scale, scale, scale);
        loadedModel.position.set(0, -2, 0);

        // 将加载后的模型设置为当前显示的模型
        setModel(loadedModel);

        // 如果存在旧的动画混合器，则停止所有动画，并取消之前的动画更新循环（如果有的话）
        if (mixer.current) {
          mixer.current.stopAllAction();

          // 如果有正在运行的动画帧，取消它
          if (animationFrameId) {
            cancelAnimationFrame(animationFrameId);
          }

          // 重置当前播放的动画动作引用
          currentAction = null;
        }

        // 创建新的动画混合器，关联到当前加载的模型
        mixer.current = new THREE.AnimationMixer(loadedModel);

        // 假设我们要播放第一个动画
        const clip = gltf.animations[index];

        // 判断一个对象是否是THREE.Mesh类型的函数，用于筛选模型中的网格对象
        function isMesh(object: THREE.Object3D): object is THREE.Mesh {
          return object instanceof THREE.Mesh; // 如果对象是THREE.Mesh类型，返回true
        }

        // 遍历模型的所有子对象，找到网格对象并播放对应的动画动作
        loadedModel.traverse((child) => {
          if (child && isMesh(child) && mixer.current) {
            // 为当前网格对象创建动画动作，并播放它
            const action = mixer.current!.clipAction(clip);

            // 设置动画播放速度为正常速度
            action.timeScale = 0.4;

            // 设置动画结束时不保持在最后一帧
            action.clampWhenFinished = false;

            // 播放动画
            action.play();

            // 记录当前正在播放的动画动作
            currentAction = action;
          }
        });

        // 动画循环函数，根据动画是否暂停来更新动画混合器
        const animate = () => {
          requestAnimationFrame(animate); // 请求下一个动画帧

          // 如果混合器存在且动画没有暂停，更新动画状态
          if (mixer.current && !isAnimationPaused && currentAction) {
            mixer.current.update(0.01); // 更新动画
          }
        };

        // 开始动画循环
        animationFrameId = requestAnimationFrame(animate);
      },
      undefined, // 加载进度回调（这里不使用）
      (error) => {
        // 处理加载模型时的错误
        console.error("Error loading model:", error);
      }
    );

    // 组件卸载时的清理操作
    return () => {
      if (mixer.current) {
        mixer.current.stopAllAction(); // 停止所有动画
        if (animationFrameId) {
          cancelAnimationFrame(animationFrameId); // 取消动画帧请求
        }
      }
    };
  }, [modelUrl, index]); // 依赖项：当模型URL或索引变化时重新加载

  return (
    <div className="aaa">
      <Canvas>
        {/* 设置场景中的光源 */}
        <ambientLight intensity={3} />
        <directionalLight position={[10, 10, 10]} intensity={3} />

        {/* 加载并显示3D模型 */}
        {model && (
          <>
            <primitive object={model} />
            <OrbitControls />
          </>
        )}

        {/* 控制视角 */}
        <OrbitControls />
      </Canvas>

      {/* 可拖拽、可展开/收起的按钮容器 */}
      <div className="button-container" ref={dragbox}>
        <Select
          defaultValue="切换动作"
          style={{ width: 120 }}
          onChange={handleChange}
          options={[
            { value: "你没时间了" },
            { value: "转圈圈" },
            { value: "给我爬" },
            { value: "小跳一下" },
          ]}
        />
      </div>
    </div>
  );
};

export default ThreeScene;
